﻿using System;
using System.Collections.Generic;
using System.Text;
using Iesi.Collections.Generic;
using TestKontrole2.iznimke;

namespace TestKontrole2 {
    public class Kontrola {

        #region Granice za dopustivu, ocekivanu stopu i kontrolni rizik
        private float MINIMALNA_GRANICA = 0.0F;
        private float MAKSIMALNA_GRANICA = 0.25F;
        #endregion

        private int id;
        private int indeksSljedece;
        private int velicinaPopulacije;
        private int velicinaUzorka;
        private Uzorak basicUzorak;
        private ISet<ElementKontrole> elementiKontrole;
        private ISet<ElementKontrole> dodatneStavke;

        private RevizijskiCiklus revCik;
        private string nazivKontrole;
        private float dopustivaStopaDevijacije;
        private float kontrolniRizik;
        private float ocekivanaStopaDevijacija;
        private string opisKontrole;
        private string odlukaRevizora;
        private int brojDevijacija;
        private int dopustivBrojDevijacija;
        IKontrolaStrategy konUti;

        virtual public string NazivKontrole {
            get { return nazivKontrole; }
            set { nazivKontrole = value; }
        }
        virtual public float DopustivaStopaDevijacije {
            get { return dopustivaStopaDevijacije; }
            set {
                if ((value <= MINIMALNA_GRANICA)&& (value > MAKSIMALNA_GRANICA))
                    throw new DopustivaStopaDevijacijeNevazeca();
                dopustivaStopaDevijacije = value; 
            }
        }
        virtual public float OcekivanaStopaDevijacija {
            get { return ocekivanaStopaDevijacija; }
            set {
                if ((value < MINIMALNA_GRANICA) && (value > MAKSIMALNA_GRANICA))
                    throw new OcekivanaStopaDevijacijeNevazeca();
                ocekivanaStopaDevijacija = value; }
        }
        virtual public float KontrolniRizik {
            get { return kontrolniRizik; }
            set {
                if ((value <= MINIMALNA_GRANICA) && (value > MAKSIMALNA_GRANICA))
                    throw new KontrolniRizikNevazec();
                kontrolniRizik = value; }
        }
        virtual public string OpisKontrole {
            get { return opisKontrole; }
            set { opisKontrole = value; }
        }
        virtual public string OdlukaRevizora {
            get { return odlukaRevizora; }
            set { odlukaRevizora = value; }
        }
        virtual public int DopustivBrojDevijacija {
            get { return dopustivBrojDevijacija; }
        }
        virtual public int VelicinaPopulacije {
            get { return velicinaPopulacije; }
        }


        public ISet<ElementKontrole> ElementiKontrole {
            get { return elementiKontrole; }
        }

        virtual public int Id {
            get { return id; }
            set { id = value; }
        }

        virtual public int BrojDevijacija {
            get { return brojDevijacija; }
            set { brojDevijacija = value; }
        }

        virtual public RevizijskiCiklus RevizijskiCiklus{
            get { return revCik; }
            set { revCik = value; }
        }

        virtual public ISet<ElementKontrole> DodatneStavke{
            get { return dodatneStavke; }
            set { dodatneStavke = value; }
        }

        public Kontrola(){
            indeksSljedece = -1;
        }

        /// <summary>
        /// Defaultni konstruktor koji sibne jednu kontrolu
        /// </summary>
        /// <param name="velicinaPopulacije"></param>
        public Kontrola(int velicinaPopulacije) {
            //Tesni primjerak
            string dNaziv = "Kontrola 1";
            string dOpis = "Prodajni i ugovori o najmu sy primjereno potvrdjeni za potrebe odobrenja kredita";
            float dKR = 5.0f;
            float dDSD = 6.0f;
            float dOSD = 1.0f;
            //\Tesni preimjerak
            nazivKontrole = dNaziv;
            this.opisKontrole = dOpis;
            this.kontrolniRizik = dKR;
            this.dopustivaStopaDevijacije = dDSD;
            this.ocekivanaStopaDevijacija = dOSD;
            this.velicinaPopulacije = 125000;

            BrojDevijacija = 0;
            konUti = KontrolaUtility.getInstanca();
            velicinaUzorka = konUti.velicinaStatistickogUzorka(VelicinaPopulacije, DopustivaStopaDevijacije, OcekivanaStopaDevijacija, KontrolniRizik);
        }
        /// <param name="kontrolniRizik">Prenizak rizik procjene kontrolnog rizika</param>
        /// <param name="dopustivaSD">Dopustiva stopa devijacije</param>
        /// <param name="ocekivanaSD">Ocekivana stopa devijacije</param>

        public Kontrola(string opisKontrole) {
            konUti = KontrolaUtility.getInstanca();
            this.opisKontrole = opisKontrole;
        }

        public Kontrola(string opisKontrole, int velicinaPopulacije): this(opisKontrole) {
            this.velicinaPopulacije = velicinaPopulacije;
        }

        public Kontrola(string opisKontrole, int velicinaPopulacije, float kontrolniRizik, float dopustivaSD, float ocekivanaSD)
            : this(opisKontrole, velicinaPopulacije) {
            KontrolniRizik = kontrolniRizik;
            DopustivaStopaDevijacije = dopustivaSD;
            OcekivanaStopaDevijacija = ocekivanaSD;

            BrojDevijacija = 0;
            calculateVelicinaUzorka(VelicinaPopulacije, DopustivaStopaDevijacije,
                OcekivanaStopaDevijacija, KontrolniRizik);                
        }

        public void calculateVelicinaUzorka(int VelicinaPopulacije, float DopustivaStopaDevijacije, float OcekivanaStopaDevijacija, float KontrolniRizik) {
            velicinaUzorka = konUti.velicinaStatistickogUzorka(VelicinaPopulacije, DopustivaStopaDevijacije,
                OcekivanaStopaDevijacija, KontrolniRizik);
            dopustivBrojDevijacija = calculateDopustivBrojDevijacija(velicinaUzorka, ocekivanaStopaDevijacija);
        }

        private int calculateDopustivBrojDevijacija(int velicinaUzorka, float ocekivanaStopaDevijacija) {
            return (int)Math.Ceiling(velicinaUzorka * ocekivanaStopaDevijacija);
        }

        /// <summary>
        /// Izracunata gornja stopa devijacije
        /// </summary>
        public float getIGStopaDevijacije() {
            return konUti.stopaDevijacije(getVelicinaUzorka(), getBrojDevijacija(), KontrolniRizik);
        }

        public float getStopaDevijacijaUzorka() {
            if (getVelicinaUzorka() == 0)
                return 0.0F;
            return (100 / getVelicinaUzorka()) * getBrojDevijacija();
        }
        public int getVelicinaUzorka() {
            return velicinaUzorka;
        }
        

        public int getBrojDevijacija() {
            return BrojDevijacija;
        }

        public void setUzorak(Uzorak uzorak) {
            this.basicUzorak = uzorak;
            elementiKontrole = new HashedSet<ElementKontrole>();
            foreach (IElement item in basicUzorak.getAllElement()) {
                ElementKontrole eleKon = new ElementKontrole(this, item);
                elementiKontrole.Add(eleKon);
            }
            DodatneStavke = new HashedSet<ElementKontrole>();
            foreach (IElement item in basicUzorak.getAllDodatneStavke()) {
                ElementKontrole eleKon = new ElementKontrole(this, item);
                eleKon.Ispravnost = ObiljezjeIspravnostiElementa.dodatnaStavka;
                DodatneStavke.Add(eleKon);
            }
        }
        public Uzorak getUzorak() {
            return basicUzorak;
        }
        internal void update(int p, ObiljezjeIspravnostiElementa ispravnost) {
            if (ispravnost == ObiljezjeIspravnostiElementa.neispravan) {
                BrojDevijacija++;
            } else if (ispravnost == ObiljezjeIspravnostiElementa.neodgovarajuci) {
                ElementKontrole ele = getNextDodatnaStavka();
                ele.Ispravnost = ObiljezjeIspravnostiElementa.neocijenjen;
                ele.Zamjena = true;
                elementiKontrole.Add(ele);
            }
        }

        private ElementKontrole getNextDodatnaStavka() {
            List<ElementKontrole> lista = new List<ElementKontrole>(DodatneStavke);
            indeksSljedece++;
            return lista[indeksSljedece];
        }
    }
}
